﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CodeIn.Diagnostics;

namespace CodeIn.Core.Modules {
	public abstract class BaseModule {
		/// <summary>
		/// Use this tracing instrument for general purpose traces.
		/// </summary>
		protected readonly AsyncStaticMessageHandler LocalTrace = MessageHandlers.Trace;

		/// <summary>
		/// Use this tracing instrument for debug specific traces. Be warned that a production
		/// release can remove every debug tracing.
		/// </summary>
		protected readonly AsyncStaticMessageHandler LocalDebug = MessageHandlers.Debug;

		/// <summary>
		/// Returns a lot of informations about the current module.
		/// </summary>
		public ModuleInfo Infos { get; set; }

		/// <summary>
		/// Returns the last set error.
		/// </summary>
		public string LastError { get; protected set; }

		// --------------------------------------------------------------------
		// MODULE IMPLEMENTATION API
		// --------------------------------------------------------------------

		protected abstract void InitializeOverride();
		protected abstract bool CanExecuteOverride(string[] args);
		protected abstract void ExecuteOverride(string[] args);

		/// <summary>
		/// Used mainly in the CanExecuteOverride implementation. Returns false and sets the LastError.
		/// </summary>
		protected bool False(string error) {
			LastError = error;
			return false;
		}

		/// <summary>
		/// Use it to report the progress of the module execution to the main UI.
		/// Range of percents is [0-100].
		/// </summary>
		protected void ReportProgress(int percents) {
			int nbr = percents;
			nbr = nbr < 0 ? 0 : nbr;
			nbr = nbr > 100 ? 100 : nbr;

			if (ProgressUpdated != null)
				ProgressUpdated(this, new ProgressUpdatedEventArgs(nbr));
		}

		// --------------------------------------------------------------------
		// PUBLIC API
		// --------------------------------------------------------------------

		/// <summary>
		/// Initilializes the module for later executions.
		/// </summary>
		public void Initialize() {
			InitializeOverride();
		}

		/// <summary>
		/// Returns true if the module can be executed according to the context and the given args.
		/// If not, LastError should be set to return a user-friendly error.
		/// </summary>
		public bool CanExecute(string[] args) {
			if (ExecutionTestStarted != null)
				ExecutionTestStarted(this, new EventArgs());

			bool ret = CanExecuteOverride(args);

			if (ExecutionTestEnded != null)
				ExecutionTestEnded(this, new ExecutionTestResultEventArgs(ret));

			return ret;
		}

		/// <summary>
		/// Working part of the module. Should only be called if CanExecute returned true.
		/// </summary>
		public void Execute(string[] args) {
			if (ExecutionStarted != null)
				ExecutionStarted(this, new EventArgs());

			ExecuteOverride(args);

			if (ExecutionEnded != null)
				ExecutionEnded(this, new EventArgs());
		}

		/// <summary>
		/// Safely executes a module by first calling CanExecuteOverride.
		/// </summary>
		public void SafeExecute(string[] args) {
			if (CanExecute(args)) {
				Execute(args);
			} else {
				string msg = "'";
				foreach (string arg in args)
					msg += arg + " ";
				msg = msg.Substring(0, msg.Length - 1) + "' cannot be executed.";
				LocalTrace.WriteWarningLine(msg);
				if (!string.IsNullOrEmpty(LastError)) {
					LocalTrace.Indent();
					LocalTrace.WriteLine(LastError);
					LocalTrace.Unindent();
					LastError = "";
				}
			}
		}

		// --------------------------------------------------------------------
		// EVENTS
		// --------------------------------------------------------------------

		/// <summary>
		/// Fired when the CanExecute method is called.
		/// </summary>
		public event EventHandler ExecutionTestStarted;

		/// <summary>
		/// Fired when  the CanExecute method returns.
		/// </summary>
		public event EventHandler<ExecutionTestResultEventArgs> ExecutionTestEnded;

		/// <summary>
		/// Fired when the module is executed.
		/// </summary>
		public event EventHandler ExecutionStarted;

		/// <summary>
		/// Fired when the module execution is finished.
		/// </summary>
		public event EventHandler ExecutionEnded;

		/// <summary>
		/// Fired when the module reports a progress update.
		/// </summary>
		public event EventHandler<ProgressUpdatedEventArgs> ProgressUpdated;

		/// <summary>
		/// Container for the percents of the current progress.
		/// </summary>
		public class ProgressUpdatedEventArgs : EventArgs {
			public int Percents { get; private set; }
			public ProgressUpdatedEventArgs(int percents) {
				Percents = percents;
			}
		}

		/// <summary>
		/// Container for the result of the CanExecute method.
		/// </summary>
		public class ExecutionTestResultEventArgs : EventArgs {
			public bool CanExecute { get; private set; }
			public ExecutionTestResultEventArgs(bool result) {
				CanExecute = result;
			}
		}
	}
}
